package jp.co.technotree.common.dao;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;

import jp.co.technotree.common.util.ObjectUtil;


public class HashBean extends BaseDAOBean {
	private static String CLASSNAME=HashBean.class.getName();
	private static final long serialVersionUID = 1L;
	private ArrayList<Object[]> dataRows = new ArrayList<Object[]>();;
	private HashMap<String, Integer> columnIndexMap = new HashMap<String, Integer>();
	private int filedCount = 0;
	private int currentIndex = 0;
	private Object values[] = null;
	private SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
	private SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd");
	private SimpleDateFormat sdf2 = new SimpleDateFormat("HH:mm:ss");
	private SimpleDateFormat sdf3 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	private BaseDAOBean[] instanceBeanList = null;
	private ArrayList instanceBeanArray = new ArrayList();
	private HashMap methodMap = null;
	private ColumnMap[] columnMapList = null;
	private Class instanceClass = null;
	private Object instanceObject = null;

	public HashBean(){

	}

	public HashBean(Class targetClass){
		MethodMapFactory factory = MethodMapFactory.getInstance();
		this.methodMap = factory.getMethodMap(targetClass);
		this.instanceClass = targetClass;
	}
	

	public void setFields(String filedName){
		columnIndexMap.put(filedName, new Integer(filedCount++));
		values = new Object[filedCount];
		
		if ( this.instanceClass != null ){
			// インスタンス化を行うクラスが定義されている場合
			String[] columnList = getFileds();
			ColumnMap[] columnMapList = new ColumnMap[columnList.length];
	
			for ( int i=0; i<columnList.length; i++ ){
				String columnName = columnList[i];
				String targetName = columnName;
				targetName = targetName.toLowerCase();
				targetName = targetName.replace("_", "");
				
				MethodMap method = (MethodMap) this.methodMap.get("set"+targetName);
				if ( method == null ){
					columnMapList[i] = new ColumnMap();
				}else{
					columnMapList[i] = new ColumnMap();
					columnMapList[i].columnName = columnName;
					columnMapList[i].methodMap = method;
				}
			}
			this.columnMapList = columnMapList;
		}
	}
	
	public void setFields(String[] filedNames){
		Object param[] = new Object[1];
		for ( int i=0; i<filedNames.length; i++ ){
			//BGLog.log("","","FLD:"+filedNames[i]);
			setFields(filedNames[i]);
		}
	}
	
	public void setInstanceValue(String columnName) throws Exception{
		String METHODNAME = "setInstanceValue("+columnName+")";
		int i;
		Object param[] = new Object[1];
		ColumnMap columnMap = null;
		
		for ( i=0; i<this.columnMapList.length; i++ ){
			if ( columnName.equals(this.columnMapList[i].columnName) ){
				columnMap = columnMapList[i];
				break;
			}
		}
		if ( columnMap == null ) return;
		
		MethodMap methodMap = columnMap.methodMap;
		if ( methodMap != null ){
			Method method = methodMap.getMethod();
			
			switch ( methodMap.getMethodParamType() ){
			case MethodMapFactory.TYPE_INT:
				//DBGLog.log(CLASSNAME,METHODNAME,"TYPE_INT");
				param[0] = new Integer(getInt(columnName));
				break;
			case MethodMapFactory.TYPE_LONG:
				//DBGLog.log(CLASSNAME,METHODNAME,"TYPE_LONG");
				param[0] = new Long(getLong(columnName));
				break;
			case MethodMapFactory.TYPE_STRING:
				//DBGLog.log(CLASSNAME,METHODNAME,"TYPE_STRING");
				param[0] = getString(columnName);
				break;
			case MethodMapFactory.TYPE_BIGDECIMAL:
				//DBGLog.log(CLASSNAME,METHODNAME,"TYPE_BIGDECIMAL");
				param[0] = getBigDecimal(columnName);
				break;
			case MethodMapFactory.TYPE_SQLDATE:
				//DBGLog.log(CLASSNAME,METHODNAME,"TYPE_SQLDATE");
				param[0] = getSqlDate(columnName);
				break;
			case MethodMapFactory.TYPE_SQLTIME:
				//DBGLog.log(CLASSNAME,METHODNAME,"TYPE_SQLTIME");
				param[0] = getSqlTime(columnName);
				break;
			case MethodMapFactory.TYPE_SQLTIMESTAMP:
				//DBGLog.log(CLASSNAME,METHODNAME,"TYPE_SQLTIMESTAMP");
				param[0] = getSqlTimestamp(columnName);
				break;
			default:
				param[0] = null;	
			}
			
			try {
				//DBGLog.log(CLASSNAME,METHODNAME,"Invoke:"+method.getName()+":"+param[0]);
				method.invoke(this.instanceObject,param);
			} catch (IllegalArgumentException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			} catch (InvocationTargetException e) {
				e.printStackTrace();
			}
		}
	}
	
	
	/**
	 * 
	 * @return
	 */
	public String[] getFileds(){
		Set<String> set = columnIndexMap.keySet();
		Iterator<String> ite = set.iterator();
		ArrayList<String> list = new ArrayList<String>();
		while ( ite.hasNext() ){
			String keyName = (String)ite.next();
			list.add(keyName);
		}
		String[] fields = (String[])list.toArray(new String[list.size()]);
		return fields;
	}

	/**
	 * 自動登録
	 * @param rowSet
	 * @throws SQLException
	 * @throws Exception
	 */
	public void setString(ReadOnlyRowSet rowSet) throws SQLException, Exception{
		Set<String> keySet = columnIndexMap.keySet();
		Iterator<String> iterator = keySet.iterator();
		while ( iterator.hasNext() ){
			String keyName = (String) iterator.next();
			Object objValue = rowSet.getObject(keyName);
			
			if ( objValue instanceof java.sql.Array ){
				// 配列型とする。
				setStringArray(keyName,rowSet.getStringArray(keyName));
			}else{
				// 文字列型で定義
				setString(keyName,(String)objValue);
			}
			
		}
	}
	
	/**
	 * 項目番号の取得
	 * @param columnName
	 * @return
	 * @throws Exception 
	 * @throws SQLException
	 */
	protected int getColumnIndex(String columnName) throws Exception{
		Integer columnIndex = (Integer) columnIndexMap.get(columnName);
		if ( columnIndex == null ){
			throw new Exception("項目:["+columnName+"]は存在しません。");
		}else{
			return columnIndex.intValue();
		}
	}
	
	public void add(){
		values = new Object[filedCount];
		dataRows.add(values);
		
		if ( this.instanceClass != null ){
			try {
				this.instanceObject = this.instanceClass.newInstance();
				this.instanceBeanArray.add(this.instanceObject);
			} catch (InstantiationException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}
		}
		
	}
	
	public int size(){
		return dataRows.size();
	}

	public void first(){
		currentIndex = 0;
		values = null;
	}
	
	public boolean next(){
		if ( currentIndex < dataRows.size() ){
			values = (Object[])dataRows.get(currentIndex++);
		}else{
			return false;
		}
		return true;
	}

	public void setInt(String filedName,int value) throws Exception{
		int index = getColumnIndex(filedName);
		values[index] = new Integer(value);
		if ( this.instanceClass != null ) setInstanceValue(filedName);
	}
	
	public int getInt(String filedName) throws Exception{
		int index = getColumnIndex(filedName);
		int intValue=0;
		if ( values[index] instanceof String ){
			String strValue = (String)values[index];
			intValue = Integer.parseInt(strValue);
		}else if ( values[index] instanceof Integer ){
			Integer value = (Integer)values[index];
			intValue=value.intValue();
		}
		return intValue;
	}
	
	public Integer getObjectInt(String filedName) throws Exception{
		int index = getColumnIndex(filedName);
		if ( values[index] instanceof String ){
			String strValue = (String)values[index];
			Integer value = Integer.valueOf(strValue);
			return value;
		}else if ( values[index] instanceof Integer ){
			Integer value = (Integer)values[index];
			return value;
		}
		return new Integer(0);
	}

	public void setLong(String filedName,long value) throws Exception{
		int index = getColumnIndex(filedName);
		values[index] = new Long(value);
		if ( this.instanceClass != null ) setInstanceValue(filedName);
	}
	
	public long getLong(String filedName) throws Exception{
		int index = getColumnIndex(filedName);
		long longValue=0;
		if ( values[index] instanceof String ){
			String strValue = (String)values[index];
			longValue = Long.parseLong(strValue);
		}else if ( values[index] instanceof Integer ){
			Long value = (Long)values[index];
			longValue=value.longValue();
		}
		return longValue;
	}
	
	public Long getObjectLong(String filedName) throws Exception{
		int index = getColumnIndex(filedName);
		if ( values[index] instanceof String ){
			String strValue = (String)values[index];
			Long value = Long.valueOf(strValue);
			return value;
		}else if ( values[index] instanceof Integer ){
			Long value = (Long)values[index];
			return value;
		}
		return new Long(0);
	}

	
	public void setString(String filedName,String value) throws Exception{
		int index = getColumnIndex(filedName);
		if ( value != null ){
			values[index] = new String(value);
		}else{
			values[index] = null;
		}
		if ( this.instanceClass != null ) setInstanceValue(filedName);
	}
	
	public String getString(String filedName) throws Exception{
		int index = getColumnIndex(filedName);
		String value = (String)values[index];
		return value;
	}
	
	public void setStringArray(String filedName,String[] value) throws Exception{
		int index = getColumnIndex(filedName);
		if ( value != null ){
			// 文字列配列型を再定義
			String[] arrayValue = new String[value.length];
			for ( int i=0; i<value.length; i++ ){
				arrayValue[i]=value[i];
			}
			values[index] = arrayValue;
		}else{
			values[index] = null;
		}
		if ( this.instanceClass != null ) setInstanceValue(filedName);
	}
	
	public String[] getStringArray(String filedName) throws Exception{
		int index = getColumnIndex(filedName);
		String[] value = (String[])values[index];
		return value;
	}

	/**
	 * 
	 * @param filedName
	 * @return
	 * @throws Exception
	 */
	public BigDecimal getBigDecimal(String filedName) throws Exception{
		int index = getColumnIndex(filedName);
		String value = (String)values[index];
		BigDecimal decimal = null;
		try {
			if ( value != null ){
				value = value.trim();
				decimal = new BigDecimal(value);
			}else{
				decimal = new BigDecimal(0);
			}
		}catch(Exception ex){
			decimal = new BigDecimal(0);
		}
		return decimal;
	}
	
	public Date getDate(String filedName) throws Exception{
		int index = getColumnIndex(filedName);
		String value = (String)values[index];
		Date dateValue = null;
		try {
			if ( value != null ){
				value = ObjectUtil.format(value);
				dateValue = sdf.parse(value);
			}else{
				dateValue = null;
			}
		}catch(Exception ex){
			dateValue = null;
		}
		return dateValue;
	}

	public Date getSqlDate(String filedName) throws Exception{
		int index = getColumnIndex(filedName);
		String value = (String)values[index];
		java.sql.Date dateValue = null;
		try {
			if ( value != null ){
				dateValue = java.sql.Date.valueOf(value);
			}else{
				dateValue = null;
			}
		}catch(Exception ex){
			dateValue = null;
		}
		return dateValue;
	}

	public Date getSqlTime(String filedName) throws Exception{
		int index = getColumnIndex(filedName);
		String value = (String)values[index];
		java.sql.Time dateValue = null;
		try {
			if ( value != null ){
				dateValue = java.sql.Time.valueOf(value);
			}else{
				dateValue = null;
			}
		}catch(Exception ex){
			dateValue = null;
		}
		return dateValue;
	}
	
	public Date getSqlTimestamp(String filedName) throws Exception{
		int index = getColumnIndex(filedName);
		String value = (String)values[index];
		java.sql.Timestamp dateValue = null;
		try {
			if ( value != null ){
				dateValue = java.sql.Timestamp.valueOf(value);
			}else{
				dateValue = null;
			}
		}catch(Exception ex){
			dateValue = null;
		}
		return dateValue;
	}

	public ArrayList getInstanceList(){
		return this.instanceBeanArray;
	}
	
	/**
	 * 
	 * @author tec1_21
	 *
	 */
	public class ColumnMap{
		public String columnName = null;
		public MethodMap methodMap = null;
	}

	
}
